package com.luckyframe.common.netty.jmeter;

import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.luckyframe.common.utils.StringUtils;
import com.luckyframe.common.utils.spring.SpringUtils;
import com.luckyframe.project.jmeter.jmeterNode.domain.JmeterNode;
import com.luckyframe.project.jmeter.jmeterNode.service.IJmeterNodeService;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalTime;
import java.util.Date;


public class JmeterHandler extends ChannelHandlerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(JmeterHandler.class);

    private IJmeterNodeService jmeterNodeService= SpringUtils.getBean(IJmeterNodeService.class);

    private JmeterChannelMap jmeterChannelMap= SpringUtils.getBean(JmeterChannelMap.class);

    protected ChannelHandlerContext ctx;

    /**
     * 同步标志
     */
    protected int rec;


    private int counter = 0;


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //统一转编码
        JSONObject json = JSON.parseObject(msg.toString());

        handleJmeterNode(json);
    }

    private void handleJmeterNode(JSONObject json) {

        if(StringUtils.isEmpty(json.getString("macAddr"))){
            return;
        }

        String macAddr = json.getString("macAddr");

        if ("clientUp".equals(json.get("method"))){

            String ip = json.getString("ip");
            String nodeName = json.getString("nodeName");
            String homeDir = json.get("homeDir").toString();
            int listenPort = NumberUtil.parseInt(json.get("listenPort").toString());

            int jmeterStatus =json.getIntValue("jmeterStatus");
            //根据macAddr查询，因为ip可能会变
            JmeterNode jmeterNode = jmeterNodeService.selectJmeterByMacAddr(macAddr);

            logger.info("client {} online @{} ip={}",nodeName,LocalTime.now(),ip);

            if(jmeterNode==null){
                //自动注册
                JmeterNode node=new JmeterNode();
                node.setIp(ip);
                node.setHomeDir(homeDir);
                node.setNodeName(nodeName);
                node.setStatus(jmeterStatus);
                node.setJmeterPort(listenPort);
                node.setAddTime(new Date());
                node.setMacAddr(macAddr);
                jmeterNodeService.insertJmeterNode(node);
                jmeterNode=node;

            }else{

                //如果已经存在
                jmeterNode.setIp(ip);
                jmeterNode.setStatus(jmeterStatus);
                jmeterNode.setNodeName(nodeName);
                jmeterNode.setJmeterPort(listenPort);
                jmeterNodeService.updateJmeterNode(jmeterNode);
            }

            jmeterChannelMap.put(jmeterNode.getId().toString(), ctx.channel());
            return;
        }

        if ("ping".equals(json.get("method"))){

            String ip = json.getString("ip");

            int jmeterStatus =json.getIntValue("jmeterStatus");

            JmeterNode jmeterNode = jmeterNodeService.selectJmeterByMacAddr(macAddr);
            jmeterNode.setStatus(jmeterStatus);
            jmeterNode.setIp(ip);
            jmeterNodeService.updateJmeterNode(jmeterNode);
            jmeterChannelMap.put(jmeterNode.getId().toString(), ctx.channel());

            return;
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        //channel失效，从Map中移除
        jmeterChannelMap.remove((SocketChannel) ctx.channel());

    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        logger.info("jmeter handler userEventTriggered @"+ LocalTime.now());

        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state().equals(IdleState.READER_IDLE)) {
                // 空闲40s之后触发 (心跳包丢失)
                if (counter >= 3) {
                    // 连续丢失3个心跳包 (断开连接)
                    ctx.channel().close().sync();
                    logger.error("已与" + ctx.channel().remoteAddress() + "断开连接");
                } else {
                    counter++;
                    logger.debug(ctx.channel().remoteAddress() + "丢失了第 " + counter + " 个心跳包");
                }
            }
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        this.ctx = ctx;
    }



    private static void sendMessage(ChannelHandlerContext ctx, String json) {
        ctx.channel().writeAndFlush(Unpooled.copiedBuffer((json + "$_").getBytes()));
    }

}
